package com.iphanta.community.activity.photographic.common;

import com.iphanta.community.common.utils.RedisKeyUtils;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;

/**
 * @author 墨声 E-mail: zehong.hongframe.huang@gmail.com
 * create time: 4/14/22 10:56 AM
 */
public class BallBoxCollection {

    private ReadWriteLock rwl = new ReentrantReadWriteLock();

    private Lock readLock = rwl.readLock();

    private Lock writeLock = rwl.writeLock();

    private Map<Long, BallBox> dynamic2Box = new ConcurrentHashMap<>();

    private Map<Long, BallBox> entry2Box = new ConcurrentHashMap<>();

    private List<BallBox> ballBoxes = new CopyOnWriteArrayList();

    private String activityId;

    private RedissonClient redissonClient;

    public BallBoxCollection(RedissonClient redissonClient, String activityId) {
        this.redissonClient = redissonClient;
        this.activityId = activityId;
        init();
    }

    private void init() {
        this.writeLock.lock();
        try {
            RSet<Long> entriesRSet = this.redissonClient.getSet(
                    RedisKeyUtils.INSTANCE.key("activity-post", this.activityId));
            Set<Long> entryIds = entriesRSet.readAll();

            Map<String, String> dynamicIdsMap = this.redissonClient.getBuckets()
                    .get(RedisKeyUtils.INSTANCE
                            .keys("activity-post:dynamicId", new ArrayList<>(entryIds)));

            List<String> dynamicIds = dynamicIdsMap.values().stream()
                    .filter(e -> Objects.nonNull(e)).collect(Collectors.toList());

            Map<String, BallBox> boxMap = this.redissonClient.getBuckets()
                    .get(RedisKeyUtils.INSTANCE.keys("bucket_ball_box", dynamicIds));

            for (BallBox box : boxMap.values()) {
                this.dynamic2Box.put(box.getDynamicId(), box);
                this.entry2Box.put(box.getEntryId(), box);
                this.ballBoxes.add(box);
            }
        } finally {
            this.writeLock.unlock();
        }
    }

    public List<BallBox> allBox() {
        this.readLock.lock();
        try {
            return new ArrayList<>(this.ballBoxes);
        } finally {
            this.readLock.unlock();
        }
    }


    public BallBox get(Long dynamicId) {
        try {
            this.readLock.lock();
            return this.dynamic2Box.get(dynamicId);
        } finally {
            this.readLock.unlock();
        }

    }

    private void clear() {
        this.dynamic2Box.clear();
        this.entry2Box.clear();
        this.ballBoxes.clear();
    }

    public void reset() {
        this.writeLock.lock();
        try {
            clear();
            init();
        } finally {
            this.writeLock.unlock();
        }
    }

}
